package top.zhangjianyong.tools.utils;

import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ： zhangjianyong
 * @date ： 2022/7/18 4:11 PM
 */
@Slf4j
public class FileUtil {
    private static byte[] ZIP_HEADER_1 = new byte[]{80, 75, 3, 4};
    private static byte[] ZIP_HEADER_2 = new byte[]{80, 75, 5, 6};

    /**
     * 判断文件是否为一个压缩文件
     *
     * @param file
     * @return
     */
    public static boolean isArchiveFile(MultipartFile file) throws IOException {
        if (file == null) {
            return false;
        }
        boolean isArchive = false;
        InputStream input = file.getInputStream();
        byte[] buffer = new byte[4];
        int length = input.read(buffer, 0, 4);
        if (length == 4) {
            isArchive = (Arrays.equals(ZIP_HEADER_1, buffer)) || (Arrays.equals(ZIP_HEADER_2, buffer));
        }
        return isArchive;
    }

    /**
     * 解压文件
     *
     * @param zipFile  原始文件
     * @param dest     解压路径
     * @param password 解压文件密码(可以为空)
     * @return 解压后文件列表
     */
    public static List<File> unZip(MultipartFile zipFile, String dest, String password) throws IOException {
        File file = saveFile(zipFile, dest);
        // 首先创建ZipFile指向磁盘上的.zip文件
        ZipFile zFile = new ZipFile(file);
        if (!zFile.isValidZipFile()) {
            //非压缩文件直接返回
            List<File> list = new ArrayList<>();
            list.add(file);
            return list;
        }
        zFile.setCharset(Charset.defaultCharset());
        // 解压目录
        File destDir = new File(dest);
        if (!destDir.exists()) {
            // 目标目录不存在时，创建该文件夹
            destDir.mkdirs();
        }
        if (zFile.isEncrypted()) {
            // 设置密码
            zFile.setPassword(password.toCharArray());
        }

        // 将文件抽出到解压目录(解压)
        zFile.extractAll(dest);
        //返回解压文件
        List<FileHeader> fileHeaders = zFile.getFileHeaders();
        return fileHeaders.stream()
                .filter(h -> !h.isDirectory())
                .map(h -> new File(dest + File.separator + h.getFileName()))
                .collect(Collectors.toList());
    }

    /**
     * 保存文件
     *
     * @param file
     * @param dir
     * @return
     * @throws IOException
     */
    public static File saveFile(MultipartFile file, String dir) throws IOException {
        return saveFile(file, dir, file.getOriginalFilename());
    }

    /**
     * 保存文件
     *
     * @param file
     * @param dir
     * @param name 文件名字
     * @return
     * @throws IOException
     */
    public static File saveFile(MultipartFile file, String dir, String name) throws IOException {
        File path = new File(dir);
        if (!path.exists()) {
            path.mkdirs();
        }
        String fileName = dir + File.separator + name;
        File saveFile = new File(fileName);
        IOUtils.copy(file.getInputStream(), new FileOutputStream(saveFile));
        return saveFile;
    }


    /**
     * 获取文件编码
     *
     * @param file
     * @return
     * @throws Exception
     */
    public static String getFileCharset(File file) throws IOException {
        BufferedInputStream bin = new BufferedInputStream(new FileInputStream(file));
        int p = (bin.read() << 8) + bin.read();
        bin.close();
        switch (p) {
            case 0xefbb:
                return "UTF-8";
            case 0xfffe:
                return "Unicode";
            case 0xfeff:
                return "UTF-16BE";
            default:
                return "GBK";
        }
    }


    public static String md5(InputStream inputStream) throws IOException, NoSuchAlgorithmException {
        MessageDigest MD5 = MessageDigest.getInstance("MD5");
        byte[] buffer = new byte[8192];
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            MD5.update(buffer, 0, length);
        }
        return new String(Hex.encodeHex(MD5.digest()));
    }
}
